﻿#include "PCM.h"
#include "lang/Math.h"
#include "array/Array.hpp"
using namespace yzrilyzr_array;
using namespace yzrilyzr_lang;
namespace yzrilyzr_dsp{
	float PCM::insert(float a, float b){
		return (a + b) / 2;
	}
	float PCM::ft(float al, FloatArray & y, float yoff){
		float a=0, l=(float)y.length;
		for(u_index i=0;i < l;i++) a+=(float)((y[i] + yoff) * sin(al * (u_sample)i * Math::PI * 2.0 / l));
		return a / l;
	}
	FloatArray * PCM::mono_8Bit_PCM(ByteArray & data){
		FloatArray * sh=new FloatArray(data.length);
		for(u_index i=0;i < sh->length;i++){
			(*sh)[i]=(float)data[i] * 256.0f;
		}
		return sh;
	}
	ByteArray * PCM::mono_PCM_8Bit(FloatArray & data){
		ByteArray * sh=new ByteArray(data.length);
		for(u_index i=0;i < sh->length;i++){
			if(data[i] > 32767) data[i]=32767;
			if(data[i] < -32767) data[i]=-32767;
			(*sh)[i]=(int8_t)(data[i] / 256);
		}
		return sh;
	}
	FloatArray ** PCM::stereo_8Bit_PCM(ByteArray & data){
		FloatArray * l=new FloatArray(data.length / 2);
		FloatArray * r=new FloatArray(data.length / 2);
		for(u_index i=0;i < data.length / 2;i++){
			(*l)[i]=(float)data[i * 2] * 256.0f;
			(*r)[i]=(float)data[i * 2 + 1] * 256.0f;
		}
		return new FloatArray * [2]{l, r};
	}
	ByteArray * PCM::stereo_PCM_8Bit(FloatArray & l, FloatArray & r){
		ByteArray * data=new ByteArray(l.length + r.length);
		for(u_index i=0;i < data->length / 2;i++){
			if(l[i] > 32767) l[i]=32767;
			if(l[i] < -32767) l[i]=-32767;
			if(r[i] > 32767) r[i]=32767;
			if(r[i] < -32767) r[i]=-32767;
			(*data)[i * 2]=(int8_t)(l[i] / 256);
			(*data)[i * 2 + 1]=(int8_t)(r[i] / 256);
		}
		return data;
	}
	//*********?******?*
	FloatArray * PCM::gain(FloatArray & src, float gain){
		FloatArray * newh=new FloatArray(src.length);
		for(u_index i=0;i < src.length;i++){
			(*newh)[i]=src[i] * gain;
		}
		return newh;
	}
	u_sample PCM::getTHD(DoubleArray & vdB){
		u_sample sum=0;
		for(u_index i=1;i < vdB.length;i++){
			sum+=pow(1.0 / pow(10, (vdB[i] - vdB[0]) / 10.0), 2);
		}
		return sqrt(sum);
	}
	FloatArray * PCM::mono_16Bit_PCM(ByteArray & data){
		FloatArray * left=new FloatArray(data.length / 2);
		int32_t s;
		for(u_index i=0, j=left->length, k=0;i < j;i++){
			s=data[k++] & 0xff;
			s|=(data[k++] & 0xff) << 8;
			s=(int16_t)s;
			(*left)[i]=s / 32767.0f;
		}
		return left;
	}
	ByteArray * PCM::mono_PCM_16Bit(FloatArray & left){
		ByteArray * arr=new ByteArray(left.length * 2);
		int32_t s;
		for(u_index i=0, j=left.length, k=0;i < j;i++){
			if(left[i] > 1.0f) left[i]=1.0f;
			if(left[i] < -1.0f) left[i]=-1.0f;
			s=(int32_t)(left[i] * 32767.0f);
			(*arr)[k++]=(int8_t)(s & 0xff);
			(*arr)[k++]=(int8_t)((s >> 8) & 0xff);
		}
		return arr;
	}
	FloatArray ** PCM::stereo_16Bit_PCM(ByteArray & data){
		FloatArray * left=new FloatArray(data.length / 4);
		FloatArray * right=new FloatArray(data.length / 4);
		int32_t s;
		for(u_index i=0, j=left->length, k=0;i < j;i++){
			s=data[k++] & 0xff;
			s|=(data[k++] & 0xff) << 8;
			s=(int16_t)s;
			(*left)[i]=((int16_t)s) / 32767.0f;
			s=data[k++] & 0xff;
			s|=(data[k++] & 0xff) << 8;
			s=(int16_t)s;
			(*right)[i]=((int16_t)s) / 32767.0f;
		}
		return new FloatArray * [2]{left, right};
	}
	ByteArray * PCM::stereo_PCM_16Bit(FloatArray & left, FloatArray & right){
		ByteArray * arr=new ByteArray(left.length * 4);
		int32_t s;
		for(u_index i=0, j=left.length, k=0;i < j;i++){
			if(left[i] > 1.0f) left[i]=1.0f;
			if(left[i] < -1.0f) left[i]=-1.0f;
			s=(int32_t)(left[i] * 32767.0f);
			(*arr)[k++]=(int8_t)(s & 0xff);
			(*arr)[k++]=(int8_t)((s >> 8) & 0xff);
			if(right[i] > 1.0f) right[i]=1.0f;
			if(right[i] < -1.0f) right[i]=-1.0f;
			s=(int32_t)(right[i] * 32767.0f);
			(*arr)[k++]=(int8_t)(s & 0xff);
			(*arr)[k++]=(int8_t)((s >> 8) & 0xff);
		}
		return arr;
	}
	FloatArray * PCM::mix(Array<FloatArray *> & a){
		FloatArray * b=a[0];
		for(u_index i=0, j=b->length;i < j;i++){
			float c=0;
			for(FloatArray * floats : a) c+=(*floats)[i];
			(*b)[i]=c / a.length;
		}
		return b;
	}
	FloatArray * PCM::reverse(FloatArray & a){
		FloatArray * data2=new FloatArray(a.length);
		for(u_index i=0, j=a.length;i < j;i++){
			(*data2)[a.length - 1 - i]=a[i];
		}
		return data2;
	}
	FloatArray * PCM::convertSampleRate(FloatArray & a, u_sample_rate sr){
		float b=(float)a.length / (float)sr;
		FloatArray * c=new FloatArray(sr);
		(*c)[0]=a[0];
		for(u_index i=0, j=sr - 2;i < j;i++){
			float xx=(float)i * b;
			int32_t x=(int32_t)floor(xx);
			float y1, y2;
			y1=a[x];
			if(x + 1 >= a.length) continue;
			y2=a[x + 1];
			(*c)[i + 1]=((y2 - y1) * (xx - x) + y2);
		}
		(*c)[sr - 1]=a[a.length - 1];
		return c;
	}
}